﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Hx.Infrastructure.Authorization;
using Hx.Infrastructure.Exceptions;
using Newtonsoft.Json;

namespace Hx.Infrastructure.Helpers
{
    public class WebApiHelper
    {
        public static string HostUrl;
        private static readonly HttpClient Client;

        static WebApiHelper()
        {
            Client = new HttpClient();
            Client.DefaultRequestHeaders.Connection.Add("Keep-Alive");
        }

        public static void SetBaseAddress(string url)
        {
            Client.BaseAddress = new Uri(url);
        }

        public static void SetAuthentication(string scheme, string parameter)
        {
            Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(scheme, parameter);
        }

        public static async Task<AccessTokenResult> GetCredentialGrantAutherticationAsync(string tokenUrl,
            CredentialGrantParameter param)
        {
            var dic = new Dictionary<string, string>
            {
                {"grant_type", "client_credentials"}
            };
            Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(param.ClientId + ":" + param.ClientSecret)));
            var accessToken = await PostResponseAsync<AccessTokenResult>(tokenUrl, dic);
            accessToken.LastGetTime = DateTime.Now;
            Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.AccessToken);
            return accessToken;
        }

        public static AccessTokenResult GetCredentialGrantAuthertication(string tokenUrl, CredentialGrantParameter param)
        {
            var dic = new Dictionary<string, string>
            {
                {"grant_type", "client_credentials"}
            };
            Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(param.ClientId + ":" + param.ClientSecret)));
            var accessToken = PostResponse<AccessTokenResult>(tokenUrl, dic);
            accessToken.LastGetTime = DateTime.Now;
            Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.AccessToken);
            return accessToken;
        }

        public static T GetResponse<T>(string url)
            where T : class
        {
            var task = Client.GetAsync(url, HttpCompletionOption.ResponseContentRead);
            var responseJson = task.Result.Content.ReadAsStringAsync().Result;

            if (task.Result.StatusCode != HttpStatusCode.OK)
                throw new RequestException(11, RequestType.Get, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }

        public static async Task<T> GetResponseAsync<T>(string url)
            where T : class
        {
            var task = await Client.GetAsync(url, HttpCompletionOption.ResponseContentRead);
            var responseJson = task.Content.ReadAsStringAsync().Result;

            if (task.StatusCode != HttpStatusCode.OK)
                throw new RequestException(12, RequestType.Get, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }

        public static T PostResponse<T>(string url, IEnumerable<KeyValuePair<string, string>> postContent)
            where T : class
        {
            var httpContent = (postContent == null ? null : new FormUrlEncodedContent(postContent));
            var task = Client.PostAsync(url, httpContent);
            var responseJson = task.Result.Content.ReadAsStringAsync().Result;
            if (task.Result.StatusCode != HttpStatusCode.OK)
                throw new RequestException(13, RequestType.Post, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }

        public static async Task<T> PostResponseAsync<T>(string url,
            IEnumerable<KeyValuePair<string, string>> postContent)
            where T : class
        {
            var httpContent = (postContent == null ? null : new FormUrlEncodedContent(postContent));
            var task = await Client.PostAsync(url, httpContent);
            var responseJson = task.Content.ReadAsStringAsync().Result;
            if (task.StatusCode != HttpStatusCode.OK)
                throw new RequestException(14, RequestType.Post, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }

        public static T PutResponse<T>(string url, IEnumerable<KeyValuePair<string, string>> postContent)
            where T : class
        {
            var httpContent = (postContent == null ? null : new FormUrlEncodedContent(postContent));
            var task = Client.PutAsync(url, httpContent);
            var responseJson = task.Result.Content.ReadAsStringAsync().Result;
            if (task.Result.StatusCode != HttpStatusCode.OK)
                throw new RequestException(15, RequestType.Put, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }

        public static async Task<T> PutResponseAsync<T>(string url,
            IEnumerable<KeyValuePair<string, string>> postContent)
            where T : class
        {
            var httpContent = (postContent == null ? null : new FormUrlEncodedContent(postContent));
            var task = await Client.PutAsync(url, httpContent);
            var responseJson = task.Content.ReadAsStringAsync().Result;
            if (task.StatusCode != HttpStatusCode.OK)
                throw new RequestException(16, RequestType.Put, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }

        public static T DeleteResponse<T>(string url)
            where T : class
        {
            var task = Client.DeleteAsync(url);
            var responseJson = task.Result.Content.ReadAsStringAsync().Result;
            if (task.Result.StatusCode != HttpStatusCode.OK)
                throw new RequestException(17, RequestType.Delete, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }

        public static async Task<T> DeleteResponseAsync<T>(string url)
            where T : class
        {
            var task = await Client.DeleteAsync(url);
            var responseJson = task.Content.ReadAsStringAsync().Result;
            if (task.StatusCode != HttpStatusCode.OK)
                throw new RequestException(18, RequestType.Delete, responseJson);

            return JsonConvert.DeserializeObject<T>(responseJson);
        }
    }
}